/*
 * Galaxium Messenger
 * Copyright (C) 2008 Paul Burton <paulburton89@gmail.com>
 * 
 * License: GNU General Public License (GPL)
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

using System;
using System.Collections.Generic;

using Gtk;

using Anculus.Core;
using Anculus.Gui;

using Galaxium.Core;
using Galaxium.Protocol;

namespace Galaxium.Gui.GtkGui
{
	public abstract class ContactTreeGroup
	{
		public event EventHandler<ContactEventArgs> ContactAdded;
		public event EventHandler<ContactEventArgs> ContactRemoved;
		public event EventHandler<ContactEventArgs> ContactChanged;
		
		Dictionary<IContact, TreeRowReference> _contacts = new Dictionary<IContact, TreeRowReference> ();
		
		internal TreeRowReference _ref;
		
		public abstract string Name { get; }
		
		public int Count
		{
			get { return _contacts.Count; }
		}
		
		public virtual void UpdateContacts (IEnumerable<IContact> contacts)
		{
			// First, we'll remove any contacts which are no longer present in this group
			// (Use ToArray to get a local copy as we'll be modifying the list)
			
			List<IContact> local = new List<IContact> (_contacts.Keys);
			foreach (IContact contact in local)
			{
				if (ContainsContact (contact))
				{
					// We still contain this contact, skip it
					continue;
				}
				
				// The contact is no longer present in this group, remove it
				
				OnContactRemoved (new ContactEventArgs (contact));
				
				_contacts.Remove (contact);
			}
			
			// Next, add any new contacts to the group
			
			foreach (IContact contact in contacts)
			{
				if (_contacts.ContainsKey (contact))
				{
					// We already have this contact, assume it changed
					OnContactChanged (new ContactEventArgs (contact));
					continue;
				}
				
				if (!ContainsContact (contact))
				{
					// We don't want this contact, skip it
					continue;
				}
				
				_contacts.Add (contact, null);
				
				OnContactAdded (new ContactEventArgs (contact));
			}
		}
		
		public void Clear ()
		{
			_contacts.Clear ();
		}
		
		internal TreeRowReference GetContactRef (IContact contact)
		{
			return _contacts[contact];
		}
		
		internal void SetContactRef (IContact contact, TreeRowReference reference)
		{
			_contacts[contact] = reference;
		}
		
		public abstract bool ContainsContact (IContact contact);
		
		protected virtual void OnContactAdded (ContactEventArgs args)
		{
			if (ContactAdded != null)
				ContactAdded (this, args);
		}
		
		protected virtual void OnContactRemoved (ContactEventArgs args)
		{
			if (ContactRemoved != null)
				ContactRemoved (this, args);
		}
		
		protected virtual void OnContactChanged (ContactEventArgs args)
		{
			if (ContactChanged != null)
				ContactChanged (this, args);
		}
	}
	
	public class ContactTreeRealGroup : ContactTreeGroup
	{
		IGroup _group;
		
		public IGroup Group
		{
			get { return _group; }
		}
		
		public override string Name
		{
			get { return _group.Name; }
		}
		
		public ContactTreeRealGroup (IGroup group)
		{
			_group = group;
		}
		
		public override bool ContainsContact (IContact contact)
		{
			if (!contact.Session.InContactList (contact))
				return false;
			
			IAccount account = _group.Session.Account;
			
			IConfigurationSection config = Configuration.ContactList.Section;
			bool showOffline = account.UseDefaultListView ? config.GetBool (Configuration.ContactList.ShowOfflineContacts.Name, Configuration.ContactList.ShowOfflineContacts.Default) : account.ShowOfflineContacts; 
			bool groupOffline = account.UseDefaultListView ? config.GetBool (Configuration.ContactList.GroupOfflineContacts.Name, Configuration.ContactList.GroupOfflineContacts.Default) : account.GroupOfflineContacts;
			
			if (((!showOffline) || groupOffline) &&
			    (contact.Presence.BasePresence == BasePresence.Offline))
				return false;
				
			return _group.Contains (contact);
		}
	}
	
	public class ContactTreeOnlineVirtualGroup : ContactTreeGroup
	{
		public override string Name
		{
			get { return "Online"; }
		}
		
		public override bool ContainsContact (IContact contact)
		{
			if (!contact.Session.InContactList (contact))
				return false;
			
			return contact.Presence.BasePresence != BasePresence.Offline;
		}
	}
	
	public class ContactTreeOfflineVirtualGroup : ContactTreeGroup
	{
		public override string Name
		{
			get { return "Offline"; }
		}
		
		public override bool ContainsContact (IContact contact)
		{
			if (!contact.Session.InContactList (contact))
				return false;
			
			return contact.Presence.BasePresence == BasePresence.Offline;
		}
	}
}
